﻿using AnalysisEnvironment.PackageProviders;
using NuGet.Common;
using NuGet.Packaging.Core;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
using NuGet.Versioning;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AnalysisEnvironment
{
    public class RemoteNugetPackageProvider : IPackageProvider
    {
        public string NugetUrl { get; set; }

        public const string PakcagePath = "packages";

        SourceCacheContext cache = new SourceCacheContext();

        public RemoteNugetPackageProvider(string url)
        {
            NugetUrl = url;

            if (Directory.Exists(PakcagePath) != true)
                Directory.CreateDirectory(PakcagePath);
        }

        public List<AssemblyName> SearchAssembly(AssemblyName name)
        {
            throw new NotImplementedException();
        }

        public Assembly TryLoadAssembly(AssemblyName name)
        {
            ILogger logger = NullLogger.Instance;
            CancellationToken cancellationToken = CancellationToken.None;

            SourceCacheContext cache = new SourceCacheContext();
            SourceRepository repository = Repository.Factory.GetCoreV3(NugetUrl);
            FindPackageByIdResource resource = repository.GetResourceAsync<FindPackageByIdResource>().Result;

            string packageId = name.Name;
            NuGetVersion packageVersion = new NuGetVersion(name.Version);

            var dllPath = Path.Combine(PakcagePath, $"{name.Name}.{name.Version}");
            if (Directory.Exists(dllPath) != true)
                Directory.CreateDirectory(dllPath);

            var nugetFile = Path.Combine(dllPath, $"{name.Name}.{name.Version}.nuget");
            using (FileStream fs = new FileStream(nugetFile, FileMode.OpenOrCreate))
            {
                resource.CopyNupkgToStreamAsync(packageId, packageVersion, fs, cache, logger, cancellationToken).Wait();
            }

            return null;
        }
    }
}
